=begin

<%= present :form => @record do |form|
  form.columns = [
    # simple
    {:label => 'Alpha', :value => :a},
    #
    {:label => 'Beta', :value => Present::UI::Select.new(:attr, options = {})},
    #
    {:label => 'Some Subgroup', :value => [{...}, {...}]}
    {:label => 'associated objects', :value => Present::UI::Select.new(:assoc_name, options = {})},
    {:label => 'other association', :value => Present::UI::FindOrCreate.new(:other_assoc, options = {})}
  }
  # for file uploads, need to force submit_method = :normal
  form.submit_method = :ajax
  # in case someone wants to customize where the form submits. it might be a specialty form that doesn't use edit/create.
  form.submit_to = url_for(...)
  # basic layout options ... should be an extension point for custom layouts
  form.layout = :horizontal
end %>


COLUMNS
* name is optional ... it's used as the form field name
* value data type
  - string (readonly) ... assume it creates the form field
  - symbol (attribute of object) ... automatically create form field
  - proc (custom) ... assume it creates the form field
  - UIObject ... assume it creates the form field


ASSUMPTIONS:
* @record.responds_to? :new_record?
* @record.responds_to the named attributes. A Hash *could* be used if modified to respond to keys ...

Next:
* inferred name (Present::Form::Column#name reader) ... based on self.value if self.value === Symbol
* assume activerecord? no! might want to create a form for an aggregate of objects.
* extensible column type configuration (e.g. form_ui from activescaffold)
  - select
  - find_or_create (for associations)
  - auto_complete (find_or_create for simple attributes)
* submit via ajax
* submit normally
* form column data types:
  - date, number, etc.
* subgroups - custom Column#value= setter that accepts arrays/hashes
* file uploads

=end
class Present::Form < Present::UIObject
  # the columns to display
  def columns
    @columns ||= []
  end
  def columns=(val)
    @columns = case val
    when Hash
      Column.collection_from_hash(val)
    when Array
      Column.collection_from_array(val)
    else
      val
    end
  end

  # the title of this form
  attr_accessor :title
  def title_for(object = nil)
    @title ||= (self.new_record? object) ? "Create #{object.class.to_s.titleize}" : "Update #{object.class.to_s.titleize}"
  end

  # the name of this form - not displayed to user, used to reference this form programmatically
  attr_accessor :name

  # what URL receives the form.
  # defaults to create or update depending on newness of given object.
  attr_accessor :submit_to
  def submit_for(object = nil)
    @submit_to ||= (self.new_record? object) ? 'create' : 'update'
  end

  # what HTTP method to use when submitting the form.
  # defaults based on newness of given object.
  attr_accessor :method
  def method_for(object = nil)
    @method ||= (self.new_record? object) ? :post : :put
  end

  def render(record)
    content_tag 'div', :id => "#{name}_form", :class => "present present_form" do
      content_tag 'form', :action => self.submit_for(record), :method => self.method_for(record) do
        o = ''
        o << tag(:input, :type => "hidden", :name => "_method", :value => self.method) if [:put, :delete].include?(self.method)
        o << render_group(self.columns, record)
      end
    end
  end

  protected

  def render_group(columns, record)
    content_tag 'ol' do
      columns.collect { |column|
        content_tag 'li' do
          o = content_tag 'label', column.label

          o << content_tag('div') do
            record_value = column.value_for(@view, record)
            if column.value.is_a? Symbol
              tag(:input, :type => 'text', :name => column.name, :value => record_value)
            else
              record_value
            end
          end
        end
      }.join
    end
  end

  def new_record?(object)
    object and object.respond_to? :new_record? and object.new_record?
  end

  # extra options for the List column
  class Column < Present::Column
    # TODO: example, help, or descriptive text for the field
    attr_accessor :description

    # TODO: form_ui replacement? or just simple data type?
    attr_accessor :type
  end
end